﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Common.Utilities;

namespace Workflows.Components.Entities.Distances.FieldDistances
{
    public class PostalCodeComparer :IAttributeDistanceCalcutor 
    {
        private string _Zip5Pattern = @"(\d\d\d\d\d)";
        private string _Zip9Pattern = @"(\d\d\d\d\d)\s?-\s?\d\d\d\d";
        private string _Zip9Pattern2 = @"(\d\d\d\d\d)\s?-?\s?\d\d\d\d";
        private string _UKPattern = @"[A-Z]{1,2}\d[A-Z\d]? \d[ABD-HJLNP-UW-Z]{2}";
        private string _CanadaPattern = @"[ABCEGHJKLMNPRSTVXY]\d[A-Z] \d[A-Z]\d";
        private string _GermanPattern = @"^([0124678][0-9]{4})$";
        private string _ChinaPattern = @"\d{6}";

        #region Implementation of IAttributeComparer

        /// <summary>
        /// load dictionary into memory or read config settings from file
        /// </summary>
        public void InitInMemorySettings()
        {
        }

        /// <summary>
        /// return similarity score in [0,1]
        /// 0 indicate no similarity or null match
        /// 1 indicate perfect match
        /// </summary>
        /// <param name="attrValue1"></param>
        /// <param name="attrValue2"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public double Compare(object attrValue1, object attrValue2, ref MatchResult result)
        {
            result = MatchResult.NullMatch;
            if (attrValue1 == null || attrValue2 == null)
                return 0;

            string strVal1 = attrValue1.ToString();
            string strVal2 = attrValue2.ToString();
            if (strVal1.Length == 0 || strVal2.Length == 0)
                return 0;

            try
            {
                if (strVal1.ToLower() == strVal2.ToLower())
                {
                    result = MatchResult.PerfectMatch;
                    return 1.00;
                }
                else
                {
                    // US
                    string us1 = string.Empty;
                    string us2 = string.Empty;
                    if(Regex.IsMatch(strVal1, this._Zip5Pattern))
                        us1 = Regex.Match(strVal1, this._Zip5Pattern).Groups[1].Value;
                    else if (Regex.IsMatch(strVal1, this._Zip9Pattern))
                        us1 = Regex.Match(strVal1, this._Zip9Pattern).Groups[1].Value;
                    else if (Regex.IsMatch(strVal1, this._Zip9Pattern2))
                        us1 = Regex.Match(strVal1, this._Zip9Pattern2).Groups[1].Value;
                    if (Regex.IsMatch(strVal2, this._Zip5Pattern))
                        us2 = Regex.Match(strVal2, this._Zip5Pattern).Groups[1].Value;
                    else if (Regex.IsMatch(strVal2, this._Zip9Pattern))
                        us2 = Regex.Match(strVal2, this._Zip9Pattern).Groups[1].Value;
                    else if (Regex.IsMatch(strVal2, this._Zip9Pattern2))
                        us2 = Regex.Match(strVal2, this._Zip9Pattern2).Groups[1].Value;
                    if (us1 == us2 && us2.Length>0 && us1.Length>0)
                    {
                        result = MatchResult.PerfectMatch;
                        return 1.00;
                    }
                    // UK
                    string uk1 = string.Empty;
                    string uk2 = string.Empty;
                    if(Regex.IsMatch(strVal1,this._UKPattern))
                        uk1 = Regex.Match(strVal1, this._UKPattern).Value;
                    if (Regex.IsMatch(strVal2, this._UKPattern))
                        uk2 = Regex.Match(strVal2, this._UKPattern).Value;
                    if(uk1.Length>0 && uk2.Length>0 && uk1==uk2)
                    {
                        result = MatchResult.PerfectMatch;
                        return 1.0;
                    }
                    // canada
                    string ca1 = string.Empty;
                    string ca2 = string.Empty;
                    if (Regex.IsMatch(strVal1, this._CanadaPattern))
                        ca1 = Regex.Match(strVal1, this._CanadaPattern).Value;
                    if (Regex.IsMatch(strVal2, this._CanadaPattern))
                        ca2 = Regex.Match(strVal2, this._CanadaPattern).Value;
                    if (ca1.Length > 0 && ca2.Length > 0 && ca1 == ca2)
                    {
                        result = MatchResult.PerfectMatch;
                        return 1.0;
                    }
                    // german
                    string de1 = string.Empty;
                    string de2 = string.Empty;
                    if (Regex.IsMatch(strVal1, this._GermanPattern))
                        de1 = Regex.Match(strVal1, this._GermanPattern).Value;
                    if (Regex.IsMatch(strVal2, this._GermanPattern))
                        de2 = Regex.Match(strVal2, this._GermanPattern).Value;
                    if (de1.Length > 0 && de2.Length > 0 && de1 == de2)
                    {
                        result = MatchResult.PerfectMatch;
                        return 1.0;
                    }
                    // china
                    string cn1 = string.Empty;
                    string cn2 = string.Empty;
                    if (Regex.IsMatch(strVal1, this._ChinaPattern))
                        cn1 = Regex.Match(strVal1, this._ChinaPattern).Value;
                    if (Regex.IsMatch(strVal2, this._ChinaPattern))
                        cn2 = Regex.Match(strVal2, this._ChinaPattern).Value;
                    if (cn1.Length > 0 && cn2.Length > 0 && cn1 == cn2)
                    {
                        result = MatchResult.PerfectMatch;
                        return 1.0;
                    }
                }

                result = MatchResult.NegativeMatch;
                return 0;
            }
            catch (Exception ex)
            {
                ExceptionHandler.HandlesException(ex);
                return 0.0;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="entity1"></param>
        /// <param name="entity2"></param>
        /// <param name="attrMetaData"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public double Compare(Entity entity1, Entity entity2, AttributeMetaData attrMetaData, ref MatchResult result)
        {
            Debug.Assert(!string.IsNullOrEmpty(attrMetaData.AttributeName));

            string attrName = attrMetaData.AttributeName;
            object attrValue1 = null;
            object attrValue2 = null;
            if (entity1.ComparableAttributes.ContainsKey(attrName))
                attrValue1 = entity1.ComparableAttributes[attrName];
            if (entity2.ComparableAttributes.ContainsKey(attrName))
                attrValue2 = entity2.ComparableAttributes[attrName];
            return this.Compare(attrValue1, attrValue2, ref result);
        }

        /// <summary>
        /// argument to bind attribute name
        /// </summary>
        public string[] ArgumentNames
        {
            get
            {
                return new string[] { "PostalCode" };
            }
        }

        private Dictionary<string, string> _ComparerSettings;
        public Dictionary<string, string> ComparerSettings
        {
            get
            {
                return _ComparerSettings;
            }
            set
            {
                this._ComparerSettings = value;
            }
        }

        #endregion
    }
}
